Skip to content

docs: document sink-visibility field in MCP Gateway write-sink guard policy (spec v1.15.0)#44305

Merged
lpcox merged 7 commits into
mainfrom
copilot/document-sink-visibility-field
Jul 8, 2026
Merged

docs: document sink-visibility field in MCP Gateway write-sink guard policy (spec v1.15.0)#44305
lpcox merged 7 commits into
mainfrom
copilot/document-sink-visibility-field

Conversation

Copilot AI commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Adds formal spec coverage for the two complementary defenses against the GitLost vulnerability class (private data leaking to public repos via agentic workflows): sink-visibility (output-side DIFC filtering) and forcePublicRepos (input-side repo access restriction).

MCP Gateway spec (mcp-gateway.md)

  • §4.1.3 + §4.1.3.8 — New forcePublicRepos gateway config field: when true (default), overrides the allow-only policy to repos="public" at runtime if the gateway detects a public repository. Disabled via MCP_GATEWAY_FORCE_PUBLIC_REPOS=false or by the compiler when private-to-public-flows: allow is set.
  • §10.8 — Write-Sink Guard Policy: specifies sink-visibility field semantics, the DIFC enforcement model ("public" unconditionally sets resource secrecy to {}, blocking any tainted agent regardless of accept), runtime verification behavior (defense-in-depth override at startup), and the compiler-emitted runtime expression.
  • §10.9 — Cross-Visibility Opt-Out: documents private-to-public-flows: allow frontmatter, its incompatibility with guards_mode: strict, compiler responsibilities, and the full interaction matrix.
  • §11.1.12 — T-WS-001 through T-WS-008 compliance tests; Write-Sink Guard Policy row added to compliance checklist.

JSON Schemas (both docs/public/ and pkg/workflow/)

  • New writeSinkGuardPolicyConfig definition with accept (required) and sink-visibility (optional enum: "public" | "private" | "internal").
  • Typed write-sink property added to guard-policies in both stdioServerConfig and httpServerConfig (the docs/public schema was missing guard-policies on stdio servers entirely).
  • forcePublicRepos: boolean added to gatewayConfig.
{
  "mcpServers": {
    "safe-outputs": {
      "guard-policies": {
        "write-sink": {
          "accept": ["*"],
          "sink-visibility": "public"
        }
      }
    }
  },
  "gateway": {
    "forcePublicRepos": false
  }
}

The sink-visibility value is emitted as a runtime expression by the compiler (${{ toJSON(steps.determine-automatic-lockdown.outputs.visibility) }}), so workflow authors do not set it manually.


Generated by 👨‍🍳 PR Sous Chef · 9.91 AIC · ⌖ 10.6 AIC · ⊞ 7.1K ·
Comment /souschef to run again



✨ PR Review Safe Output Test - Run 28952113419

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

💥 [THE END] — Illustrated by Smoke Claude · 64.8 AIC · ⌖ 31.5 AIC · ⊞ 8.4K ·
Comment /smoke-claude to run again


Generated by 👨‍🍳 PR Sous Chef · 6.93 AIC · ⌖ 5.06 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Copilot AI and others added 3 commits July 8, 2026 13:57
…spec

- Add Section 4.1.3.8 documenting the new `forcePublicRepos` gateway config field
- Add `forcePublicRepos` to the gateway config fields table (Section 4.1.3)
- Add Section 10.8 — Write-Sink Guard Policy with full `sink-visibility` field specification,
  enforcement model, DIFC semantics, runtime verification, and compiler behavior
- Add Section 10.9 — Cross-Visibility Opt-Out documenting `private-to-public-flows: allow`
  frontmatter option, its constraints, compiler responsibilities, and interaction matrix
- Add compliance test category 11.1.12 with T-WS-001 through T-WS-008
- Update compliance checklist with Write-Sink Guard Policy row
- Add changelog entry for spec version 1.15.0
- Update both JSON schema files (docs/public and pkg/workflow) with:
  - New `writeSinkGuardPolicyConfig` definition with `accept` and `sink-visibility` fields
  - Typed `write-sink` property in `guard-policies` for both stdioServerConfig and httpServerConfig
  - New `forcePublicRepos` boolean field in `gatewayConfig`
  - Added `guard-policies` to `stdioServerConfig` in docs/public schema (was missing)

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
…nition

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Copilot AI changed the title [WIP] Document sink-visibility field in MCP Gateway write-sink guard policy docs: document sink-visibility field in MCP Gateway write-sink guard policy (spec v1.15.0) Jul 8, 2026
Copilot finished work on behalf of lpcox July 8, 2026 14:00
Copilot AI requested a review from lpcox July 8, 2026 14:00
@lpcox lpcox marked this pull request as ready for review July 8, 2026 14:01
Copilot AI review requested due to automatic review settings July 8, 2026 14:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the MCP Gateway spec and its published/internal JSON schemas to formally specify cross-visibility protections against private-data leakage to public repositories, via the forcePublicRepos gateway behavior and the write-sink / sink-visibility DIFC policy.

Changes:

  • Adds gateway.forcePublicRepos (default true) to the spec and both JSON schemas, documenting runtime behavior and opt-out semantics.
  • Defines and documents guard-policies.write-sink with accept + optional sink-visibility (public|private|internal) in the spec and both JSON schemas.
  • Extends the MCP Gateway spec with a new compliance-test section for write-sink behavior (T-WS-001..T-WS-008) and updates the changelog/checklist.
Show a summary per file
File Description
pkg/workflow/schemas/mcp-gateway-config.schema.json Adds schema definitions for forcePublicRepos and typed guard-policies.write-sink to match the updated spec.
docs/public/schemas/mcp-gateway-config.schema.json Publishes the same schema updates for documentation consumers (including stdio server guard-policies).
docs/src/content/docs/reference/mcp-gateway.md Updates spec version to 1.15.0 and adds normative sections for forcePublicRepos, sink-visibility, opt-out semantics, and compliance tests.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 3/3 changed files
  • Comments generated: 3
  • Review effort level: Low

Comment on lines +1581 to +1584
#### 10.8.2 `sink-visibility` Field

The `write-sink` object inside `guard-policies` for a safe-outputs (or equivalent) MCP server accepts the following field:

Comment on lines +1627 to +1629
This runtime expression resolves to the actual repository visibility at workflow execution time (as determined by the automatic lockdown detection step). Workflow authors do not need to set `sink-visibility` manually — it is derived from the repository context automatically.

**Configuration Example** (as rendered in the generated config):
Comment on lines +562 to +565
When `forcePublicRepos` is `true` (the default), the gateway overrides the compiled allow-only policy to `repos="public"` at startup if it detects the workflow is running in a public repository. This prevents agents from accumulating private-data secrecy tags in the first place — even when the compiled config grants broader access.

**Detection mechanism**: The gateway reads `GITHUB_REPOSITORY` and calls `GET /repos/{owner}/{repo}` at startup to determine repository visibility. If the repository is public and `forcePublicRepos` is `true`, the override is applied unconditionally.

@pelikhan

pelikhan commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

@copilot use consistent among comventions

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

@copilot use consistent among comventions

Fixed three inconsistencies in the spec (commit docs: fix grammar, wording, and contradiction):

  1. Grammar (§10.8.2): "accepts the following field" → "fields" (two fields are listed).
  2. Wording (§10.8.5): Config example label changed from "as rendered in the generated config" to "resolved runtime value — "public" shown as an example after the expression is evaluated" to clarify the snippet shows a post-evaluation value, not the raw generated expression.
  3. Contradiction (§4.1.3.8): Removed "unconditionally" from the detection mechanism description; replaced with a forward reference to the precedence rules that list the actual gating conditions.

Copilot AI requested a review from pelikhan July 8, 2026 14:14
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any remaining unresolved review feedback, and rerun checks once the branch is up to date.

Generated by 👨‍🍳 PR Sous Chef · 9.91 AIC · ⌖ 10.6 AIC · ⊞ 7.1K ·
Comment /souschef to run again

Copilot AI commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any remaining unresolved review feedback, and rerun checks once the branch is up to date.

...

All local validation passes and the branch is up to date with main (merge commit f94d875).

Reviews: Three copilot-pull-request-reviewer[bot] threads — all is_outdated on the current HEAD; the fixes were applied in commit 804b963:

  • Grammar (§10.8.2): "accepts the following field" → "fields"
  • Wording (§10.8.5): config example relabeled as resolved runtime value
  • Contradiction (§4.1.3.8): "unconditionally" removed, gating conditions referenced

GraphQL API returns 403 so threads cannot be programmatically resolved — they will dismiss when a reviewer re-reviews.

Checks (local): make fmt ✅ · make lint ✅ (0 errors, warnings pre-existing) · make test-unit ✅ · make recompile ✅ · make agent-report-progress

Checks (CI): Stale after agent push; needs human re-trigger (close/reopen PR or push from maintainer).

Mergeable: PR is open, not draft, branch is up to date. mergeable_state: unstable reflects the stale CI status.

Hand-off: CI must be re-triggered by a maintainer before merge.

Copilot AI requested a review from gh-aw-bot July 8, 2026 14:32
@lpcox lpcox added the smoke label Jul 8, 2026
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

💥 Smoke Test: Claude — Run 28952113419

Core #1-12: ✅ all passed
PR Review #13-17: ✅ all passed
#18 Push to branch: ⚠️ skipped (branch history modifies files outside allowed-files config)
#19 Close PR: ⚠️ skipped (no safe test PR)

Overall: PARTIAL (all executed tests passed; 2 skipped)

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

💥 [THE END] — Illustrated by Smoke Claude · 64.8 AIC · ⌖ 31.5 AIC · ⊞ 8.4K ·
Comment /smoke-claude to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💥 Automated smoke test review - all systems nominal!

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

💥 [THE END] — Illustrated by Smoke Claude · 64.8 AIC · ⌖ 31.5 AIC · ⊞ 8.4K
Comment /smoke-claude to run again

},
"default": ["*"]
},
"guard-policies": {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition of the write-sink guard policy reference here — consider adding a schema example in the description for clarity.

| `keepaliveInterval` | integer | No | Keepalive ping interval in seconds for HTTP MCP backends. Prevents session expiry during long-running tasks. Use `-1` to disable, `0` or unset for gateway default (1500s = 25 min), or a positive integer for a custom interval. |
| `sessionTimeout` | string | No | Session timeout for MCP gateway sessions as a Go duration string (e.g. `"30m"`, `"4h"`, `"24h"`). Empty or omitted uses the gateway default (6h). Must be at least 5m when set by the workflow compiler (no upper bound; infrastructure operators may override via `MCP_GATEWAY_SESSION_TIMEOUT` env var). |
| `opentelemetry` | object | No | OpenTelemetry configuration for emitting distributed tracing events for MCP calls. See Section 4.1.3.7 for details. |
| `forcePublicRepos` | boolean | No | When `true` (default), forces the allow-only policy to `repos="public"` at runtime if the gateway detects it is running in a public repository. When `false`, disables this override — set by the compiler when `private-to-public-flows: allow` is declared in workflow frontmatter. See Section 4.1.3.8 for details. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good documentation of forcePublicRepos — the default behavior is clearly explained. Consider cross-linking to the DIFC secrecy tags section.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Smoke test: FAIL
Merged PRs: #44308 docs(parser): document missing internal dependencies in README; #44288 add smoke-copilot-small workflow to validate model: small alias resolution
GitHub MCP: PASS
Serena: PASS
Playwright: PASS
Web-fetch: FAIL (tool unavailable)
Set issue field: SKIPPED (no editable fields available)

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex · 4.41 AIC · ⌖ 3.35 AIC · ⊞ 12.3K ·
Comment /smoke-codex to run again

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Comment Memory

Quiet build scripts hum
Checks gather in the morning
Signals keep their shape

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex · 4.41 AIC · ⌖ 3.35 AIC · ⊞ 12.3K ·
Comment /smoke-codex to run again

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Comment Memory

Smoke drum beat loud
Tiny test club hit dark rock
Bot grin, sparks still jump

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

📰 BREAKING: Report filed by Smoke Copilot · 98.6 AIC · ⌖ 4.87 AIC · ⊞ 19.1K ·
Comment /smoke-copilot to run again
Add label smoke to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Smoke run done. Two cave marks left inline.

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

📰 BREAKING: Report filed by Smoke Copilot · 98.6 AIC · ⌖ 4.87 AIC · ⊞ 19.1K
Comment /smoke-copilot to run again
Add label smoke to run again

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Smoke tests:

  • T1 ✅
  • T2 ✅
  • T3 ❌
  • T4 ✅
  • T5 ✅
  • T6 ✅
  • T7 ❌
    Overall: FAIL

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • accounts.google.com
  • android.clients.google.com
  • clients2.google.com
  • contentautofill.googleapis.com
  • safebrowsingohttpgateway.googleapis.com
  • www.google.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "accounts.google.com"
    - "android.clients.google.com"
    - "clients2.google.com"
    - "contentautofill.googleapis.com"
    - "safebrowsingohttpgateway.googleapis.com"
    - "www.google.com"

See Network Configuration for more information.

📰 BREAKING: Report filed by Smoke Copilot - AOAI (Entra) · 40.9 AIC · ⌖ 3.03 AIC · ⊞ 17.6K ·
Comment /smoke-copilot-aoai-entra to run again
Add label smoke to run again

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, ensure the branch is up to date, and rerun checks.

Generated by 👨‍🍳 PR Sous Chef · 6.93 AIC · ⌖ 5.06 AIC · ⊞ 7.1K ·
Comment /souschef to run again

… net

- Add sinkVisibilityExemptServers to gateway config fields table (section 4.1.3)
- Add to JSON schemas in both docs/public and pkg/workflow
- Document default sink-visibility="public" for non-safe-outputs (section 10.8.6)
- Document safe-outputs runtime safety net (section 10.8.7)
- Expand section 10.9 to support list form of private-to-public-flows
- Add compiler responsibilities for list form (validation + config emission)
- Update interaction matrix with list form compatibility

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@lpcox lpcox merged commit d4fdc96 into main Jul 8, 2026
29 checks passed
@lpcox lpcox deleted the copilot/document-sink-visibility-field branch July 8, 2026 16:22
Copilot stopped work on behalf of gh-aw-bot due to an error July 8, 2026 16:22
lpcox added a commit to github/gh-aw-mcpg that referenced this pull request Jul 8, 2026
## Summary

Adds the same `forcePublicRepos` defense-in-depth runtime check to the
CLI proxy (`awmg proxy`) that already exists in the MCP gateway (unified
mode).

## Problem

The proxy receives its allow-only policy as a pre-built `--policy` JSON
string from the compiler. If the compiler misconfigures the policy
(e.g., `repos: "all"` when the workflow repo is public), the proxy would
trust it and allow the agent to read private repos through the `gh` CLI.

## Solution

Before passing the policy to the WASM guard, the proxy now:
1. Reads `GITHUB_REPOSITORY` 
2. Calls `GET /repos/{owner}/{repo}` to verify visibility
3. If the repo is **public**, overrides `repos` to `"public"` in the
allow-only policy

This prevents agents in public-repo workflows from reading private
repos, regardless of what policy the compiler passed.

## Opt-out

Set `MCP_GATEWAY_FORCE_PUBLIC_REPOS=false` to disable (set by the
compiler when `private-to-public-flows: allow` is declared in workflow
frontmatter).

## Fail-open semantics

The override is skipped when:
- `MCP_GATEWAY_FORCE_PUBLIC_REPOS=false`
- `GITHUB_REPOSITORY` is not set
- No GitHub token is available
- The API call fails

In these cases, the compiled policy is used as-is.

## Companion PR

- github/gh-aw#44305 — spec documentation for `forcePublicRepos` and
sink-visibility
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.82.7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spec: document sink-visibility field in MCP Gateway write-sink guard policy

5 participants